#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "log.hpp"

enum
{
    SocketErr = 2,
    BindErr,
    ListenErr,
};

const int backlog = 10;

class St
{
public:
    int Socket()
    {
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0)
        {
            lg(FATAL, "socket fd failed! %d:%s", errno, strerror(errno));
            exit(SocketErr);
        }
        return sockfd_;
    }
    void Bind(uint16_t port) // 服务器绑定的是任意ip
    {
        // 网络结构体
        struct sockaddr_in local;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_family = AF_INET;
        local.sin_port = htons(port);

        if (bind(sockfd_, (sockaddr *)&local, sizeof(local)))
        {
            lg(FATAL, "bind failed! %d:%s", errno, strerror(errno));
            exit(BindErr);
        }
    }
    void Listen()
    {
        if (listen(sockfd_, backlog))
        {
            lg(FATAL, "listen failed! %d:%s", errno, strerror(errno));
            exit(ListenErr);
        }
    }
    int Accept(std::string *clientip, uint16_t *clientport)
    {
        int rwfd;
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        rwfd = accept(sockfd_, (sockaddr *)&peer, &len);
        if (rwfd == -1)
        {
            // lg(WARNING, "accept failed! %d:%s", errno, strerror(errno));
        }
        char ip_buffer[256];
        inet_ntop(AF_INET, &peer.sin_addr.s_addr, ip_buffer, sizeof(ip_buffer));
        *clientip = ip_buffer;
        *clientport = ntohs(peer.sin_port);
        return rwfd;
    }
    bool Connect(const char *ip, const char* port)
    {
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        inet_pton(AF_INET, ip, &server.sin_addr.s_addr);
        server.sin_port = htons(std::stoi(port));
        socklen_t len = sizeof(server);
        int r = connect(sockfd_,(sockaddr*)&server,len);
        if(r == -1)
            return false;
        else
            return true;
    }
    void Close()
    {
        close(sockfd_);
    }
    int Fd()
    {
        return sockfd_;
    }

private:
    int sockfd_;
};
